package top.v5it.japi.plus.data.support.repository.impl;

import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import top.v5it.japi.plus.data.support.entity.*;
import top.v5it.japi.plus.data.support.repository.EntityDataRepository;

import javax.persistence.EntityManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * JPA实现获取框架支持必要实体数据服务
 *
 * @author zhanpu
 * @date 2022/6/13
 */
@AllArgsConstructor
public class JpaEntityDataRepository implements EntityDataRepository {

    private static final Map<Integer, String> CERT_FIELD;
    private static final Map<Integer, String> CLIENT_CERT_FIELD;
    private static final Map<Integer, String> CHANNEL_FIELD;
    private static final Map<Integer, String> SITECHANNEL_FIELD;
    private static final Map<Integer, String> KEYCHANNEL_FIELD;

    static {
        CERT_FIELD = new HashMap<Integer, String>() {

            private static final long serialVersionUID = -79110038149238339L;

            {
                put(0, "name");
                put(1, "publicKey");
                put(2, "privateKey");
                put(3, "serialNo");
                put(4, "startTime");
                put(5, "endTime");
            }
        };

        CLIENT_CERT_FIELD = new HashMap<Integer, String>() {

            private static final long serialVersionUID = -287206621696632066L;

            {
                put(0, "clientId");
                put(1, "name");
                put(2, "publicKey");
                put(3, "privateKey");
                put(4, "serialNo");
                put(5, "startTime");
                put(6, "endTime");
            }
        };

        CHANNEL_FIELD = new HashMap<Integer, String>() {

            private static final long serialVersionUID = -826356773048588588L;

            {
                put(0, "channel");
                put(1, "name");
                put(2, "startTime");
                put(3, "endTime");
            }
        };

        SITECHANNEL_FIELD = new HashMap<Integer, String>() {

            private static final long serialVersionUID = 6102744476487952279L;

            {
                put(0, "status");
                put(1, "channel");
                put(2, "siteId");
                put(3, "startTime");
                put(4, "endTime");
            }
        };

        KEYCHANNEL_FIELD = new HashMap<Integer, String>() {

            private static final long serialVersionUID = -6992620754622862333L;

            {
                put(0, "channel");
                put(1, "name");
                put(2, "aesKey");
                put(3, "signKey");
                put(4, "startTime");
                put(5, "endTime");
            }
        };
    }

    private final EntityManager em;

    /**
     * 将数据转换成map
     */
    private static final BiFunction<Object[], Map<Integer, String>, Map<String, Object>> MAPPER = (t, u) -> {
        Map<String, Object> result = new HashMap<>(t.length);
        u.forEach((key, value) -> result.put(value, Objects.toString(t[key])));
        u.clear();
        return result;
    };

    @SuppressWarnings("unchecked")
    private <T> List<T> list(final String sql, final Map<Integer, String> filed, final Class<T> clazz) {
        List<Object[]> resultList = em.createNativeQuery(sql)
                .getResultList();

        return resultList.stream()
                .map(v -> MAPPER.apply(v, filed))
                .map(v -> BeanUtil.toBean(v, clazz))
                .collect(Collectors.toList());
    }

    @Override
    public List<Cert> certs() {
        return list(EntityDataRepository.SELECT_CERTS, CERT_FIELD, Cert.class);
    }

    @Override
    public List<Channel> channels() {
        return list(EntityDataRepository.SELECT_CHANNELS, CHANNEL_FIELD, Channel.class);
    }

    @Override
    public List<ClientCert> clientCerts() {
        return list(EntityDataRepository.SELECT_CLIENTCERTS, CLIENT_CERT_FIELD, ClientCert.class);
    }

    @Override
    public List<SiteChannel> siteChannels() {
        return list(EntityDataRepository.SELECT_SITECHANNELS, SITECHANNEL_FIELD, SiteChannel.class);
    }

    @Override
    public List<KeyChannel> keyChannels() {
        return list(EntityDataRepository.SELECT_KEYCHANNELS, KEYCHANNEL_FIELD, KeyChannel.class);
    }
}
